package com.ibeeking.found.upms.cp.rest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ibeeking.found.common.entity.CurrentUser;
import com.ibeeking.found.common.enums.FrontendTypeEnum;
import com.ibeeking.found.upms.api.common.dto.PermissionDTO;
import com.ibeeking.found.upms.api.feign.UpmsGClient;
import com.ibeeking.found.upms.cp.rest.service.ICpPermissionService;
import com.ibeeking.found.upms.cp.rest.service.ICpRolePermissionService;
import com.ibeeking.found.upms.cp.rest.service.ICpRoleService;
import com.ibeeking.found.upms.cp.rest.service.ICpUserRoleService;
import com.ibeeking.found.upms.service.common.bo.CpPermissionBO;
import com.ibeeking.found.upms.service.common.bo.CpRolePermissionBO;
import com.ibeeking.found.upms.service.common.bo.CpUserFavorityBO;
import com.ibeeking.found.upms.service.common.bo.CpUserRoleBO;
import com.ibeeking.found.upms.service.common.constants.RedisKeyConstant;
import com.ibeeking.found.upms.service.common.dos.CpPermissionDO;
import com.ibeeking.found.upms.service.common.dos.CpTpPermissionDO;
import com.ibeeking.found.upms.service.common.dos.CpUserPermissionFavorityDO;
import com.ibeeking.found.upms.service.common.param.UserPermissionParam;
import com.ibeeking.found.upms.service.common.vo.CurrentPermissionVO;
import com.ibeeking.found.upms.service.common.vo.PermissionTreeVO;
import com.ibeeking.found.upms.service.mapper.CpPermissionMapper;
import com.ibeeking.found.upms.service.mapper.CpTpPermissionMapper;
import com.ibeeking.found.upms.service.mapper.CpUserPermissionFavorityMapper;
import com.ibeeking.nematos.redis.utils.RedisUtils;
import com.ibeeking.nematos.utils.data.Collections3;
import com.ibeeking.nematos.utils.data.TreeFastUtils;
import com.ibeeking.nematos.utils.id.IdGenerator;
import com.ibeeking.nematos.utils.json.JsonUtils;
import com.ibeeking.nematos.utils.result.ResponseResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassName CpPermissionServiceImpl
 * @Description
 * @Author ibeeking
 * @Date 2021-02-22 13:37
 **/
@Service
public class CpPermissionServiceImpl implements ICpPermissionService {

    @Resource
    private CpPermissionMapper cpPermissionMapper;
    @Resource
    private CpUserPermissionFavorityMapper cpUserPermissionFavorityMapper;
    @Resource
    private ICpUserRoleService userRoleServiceImpl;
    @Resource
    private ICpRolePermissionService rolePermissionServiceImpl;

    @Resource
    private ICpRoleService roleServiceImpl;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private UpmsGClient upmsGClient;

    @Override
    public List<CpPermissionBO> selectAllList() {
        List<CpPermissionDO> csPermissionDos = cpPermissionMapper.selectList(Wrappers.emptyWrapper());
        if (Collections3.isEmpty(csPermissionDos)) {
            return Collections3.emptyList();
        }
        ResponseResult<List<PermissionDTO>> responseResult = upmsGClient.queryAllList(Arrays.asList(FrontendTypeEnum.CP.getCode()));
        if (null == responseResult || Collections3.isEmpty(responseResult.getData())) {
            return Collections3.emptyList();
        }
        List<PermissionTreeVO> permissionTreeVos = JsonUtils.jsonToList(responseResult.getData(), PermissionTreeVO.class);

        List<Long> haveIds = csPermissionDos.stream().map(CpPermissionDO::getId).collect(Collectors.toList());
        List<Long> resultIds = new ArrayList<>();
        TreeFastUtils.selectLongPidByCid(resultIds, permissionTreeVos, haveIds);
        resultIds.addAll(haveIds);
        List<PermissionTreeVO> collect = permissionTreeVos.stream().filter(s -> resultIds.contains(s.getId())).collect(Collectors.toList());
        return JsonUtils.jsonToList(collect, CpPermissionBO.class);
    }

    @Override
    public List<CurrentPermissionVO> queryEffectiveList(CurrentUser currentUser, String jti) {
        List<CurrentPermissionVO> result;
        //1 从缓存中查询
        //从缓存中查询用户权限
        Object o = redisUtils.get(RedisKeyConstant.MODULE_CP + RedisKeyConstant.USER_PERMISSION + currentUser.getTenantId() + currentUser.getId() + ":" + jti);
        if (null != o) {
            result = JsonUtils.jsonToList(o, CurrentPermissionVO.class);
        } else {
            //3 根据当前登录用户获取当前角色
            List<CpUserRoleBO> csUserRoleBos = userRoleServiceImpl.queryUserRoleByUserIds(Arrays.asList(currentUser.getId()));
            if (Collections3.isEmpty(csUserRoleBos)) {
                return Collections3.emptyList();
            }
            List<Long> roleIds = csUserRoleBos.stream().map(CpUserRoleBO::getRoleId).collect(Collectors.toList());
            Long administratorId = roleServiceImpl.selectAdministratorId();
            boolean administrator = roleIds.contains(administratorId);
            //查询所有菜单
            List<CpPermissionBO> csPermissionBos = selectAllList();
            if (Collections3.isEmpty(csPermissionBos)) {
                return Collections3.emptyList();
            }
            result = JsonUtils.jsonToList(csPermissionBos, CurrentPermissionVO.class);
            if (!administrator) {
                //4 根据角色查询权限
                List<CpRolePermissionBO> csRolePermissionBos = rolePermissionServiceImpl.queryRolePermissionByRoleIds(roleIds);
                if (Collections3.isEmpty(csRolePermissionBos)) {
                    return Collections3.emptyList();
                }
                List<Long> currentIds = csRolePermissionBos.parallelStream().map(CpRolePermissionBO::getPermissionId).collect(Collectors.toList());
                //5 根据权限查询所有上级权限
                List<Long> resultIds = new ArrayList<>();
                TreeFastUtils.selectLongPidByCid(resultIds, result, currentIds);
                resultIds.addAll(currentIds);
                result = result.stream().filter(currentPermissionVO -> resultIds.contains(currentPermissionVO.getId())).collect(Collectors.toList());
            }

            if (!Collections3.isEmpty(result)) {
                //7 存入缓存
                redisUtils.set(RedisKeyConstant.MODULE_CP + RedisKeyConstant.USER_PERMISSION + currentUser.getTenantId() + currentUser.getId() + ":" + jti, result, RedisKeyConstant.HALF_DAY);
            }
        }
        //8 转换数据格式并返回
        return result;
    }

    @Override
    public List<CpUserFavorityBO> queryUserPermissionFavorityByUserId(Long userId) {
        if(userId == null) return Collections3.emptyList();
        List<CpUserPermissionFavorityDO> tenantUserPermissionFavorityDOS = cpUserPermissionFavorityMapper.queryPermissionFavorityByUserIds(userId);
        if(Collections3.isEmpty(tenantUserPermissionFavorityDOS)) return Collections3.emptyList();
        return JsonUtils.jsonToList(tenantUserPermissionFavorityDOS, CpUserFavorityBO.class);
    }

    @Override
    public List<CpPermissionBO> queryUserPermissionFavorityList(CurrentUser currentUser) {
        Long userId = currentUser.getId();
        if(userId == null) return Collections3.emptyList();
        List<CpUserPermissionFavorityDO> tenantUserPermissionFavorityDOS = cpUserPermissionFavorityMapper.queryPermissionFavorityByUserIds(userId);
        if(Collections3.isEmpty(tenantUserPermissionFavorityDOS)) return Collections3.emptyList();
        List<Long> haveIds = tenantUserPermissionFavorityDOS.stream().map(CpUserPermissionFavorityDO::getPermissionId).collect(Collectors.toList());

        ResponseResult<List<PermissionDTO>> responseResult = upmsGClient.queryListByIds(haveIds);
        if (null == responseResult || Collections3.isEmpty(responseResult.getData())) {
            return Collections3.emptyList();
        }
        List<PermissionTreeVO> permissionTreeVos = JsonUtils.jsonToList(responseResult.getData(), PermissionTreeVO.class);

        return JsonUtils.jsonToList(permissionTreeVos, CpPermissionBO.class);
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Boolean addAndUpdateUserPermissionFavority(CurrentUser currentUser, UserPermissionParam param) {
        Long userId = currentUser.getId();
        if(userId == null ) return true;
        if (null == param.getPermissionIds() || 0 == param.getPermissionIds().length) {
            return true;
        }
        cpUserPermissionFavorityMapper.delete(new LambdaQueryWrapper<CpUserPermissionFavorityDO>().eq(CpUserPermissionFavorityDO::getUserId,userId));
        List<Long> paramIds = Arrays.asList(param.getPermissionIds());
        List<CpUserPermissionFavorityDO> saves = new ArrayList<>();
        paramIds.stream().forEach(key -> {
            CpUserPermissionFavorityDO userPermissionFavorityDO = new CpUserPermissionFavorityDO();
            userPermissionFavorityDO.setId(IdGenerator.getId());
            userPermissionFavorityDO.setUserId(userId);
            userPermissionFavorityDO.setPermissionId(key);
            saves.add(userPermissionFavorityDO);
        });
        return cpUserPermissionFavorityMapper.insertBatchSomeColumn(saves) >0;
    }

}
